package com.anti.jdbc.support;

import com.anti.commom.core.exception.DatabaseException;
import com.anti.commom.core.utils.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description TODO
 * @Author anTi
 * @Date 2021-3-13
 */
public class SqlUtils {
    private static Pattern ORDER_PATTERN = Pattern.compile("order\\s*by[\\s\\S]*", 2);


    public static String buildLimitSql(String sql, DataBaseType dbtype, long firstRow, long limitRow) {
        StringBuilder pagingSelect;
        switch(dbtype) {
            case MYSQL:
                pagingSelect = new StringBuilder(sql.length() + 100);
                pagingSelect.append("select * from (");
                pagingSelect.append(sql);
                pagingSelect.append(") as qt limit ");
                if (firstRow > 0L) {
                    pagingSelect.append(firstRow);
                    pagingSelect.append(",");
                }

                pagingSelect.append(limitRow);
                return pagingSelect.toString();
            case ORACLE:
                pagingSelect = new StringBuilder(sql.length() + 100);
                if (firstRow > 0L) {
                    pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ").append(sql).append(" ) row_  where rownum <= ").append(firstRow + limitRow).append(") r_ where rownum_ > ").append(firstRow);
                } else {
                    pagingSelect.append("select * from ( ").append(sql).append(" ) r_ where rownum <= ").append(limitRow);
                }

                return pagingSelect.toString();
            default:
                throw new DatabaseException("该类型数据库暂不支持");
        }
    }


    public static SqlArgument getSqlArgument(String sql, Object[] params) {
        SqlArgument sqlArgument = new SqlArgument();
        if (params.length == 1 && params[0] instanceof Map) {
            sqlArgument.setText(sql);
            sqlArgument.setNamedQuery(true);
            sqlArgument.setParamMap((Map)params[0]);
            return sqlArgument;
        } else {
            boolean hasMultiValue = false;
            Object[] arr$ = params;
            int len$ = params.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                Object param = arr$[i$];
                if (param != null) {
                    if (param instanceof Collection) {
                        hasMultiValue = true;
                        break;
                    }

                    if (param.getClass().isArray()) {
                        hasMultiValue = true;
                        break;
                    }
                }
            }

            if (hasMultiValue) {
                String[] sqlSections = StringUtils.splitPreserveAllTokens(sql, "?");
                StringBuilder sb = new StringBuilder(sql.length());
                List<Object> args = new ArrayList();
                sb.append(sqlSections[0]);

                for(int i = 0; i < params.length; ++i) {
                    Object param = params[i];
                    String seq = "?";
                    if (param != null) {
                        if (param instanceof Collection) {
                            Collection collection = (Collection)param;
                            args.addAll(collection);
                            seq = StringUtils.repeat("?", ",", collection.size());
                        } else if (param.getClass().isArray()) {
                            Object[] arr = ((Object[])param);
                            args.addAll(Arrays.asList(arr));
                            seq = StringUtils.repeat("?", ",", args.size());
                        } else {
                            args.add(param);
                        }
                    } else {
                        args.add(null);
                    }

                    sb.append(seq).append(sqlSections[i + 1]);
                }

                sqlArgument.setText(sb.toString());
                sqlArgument.setArgs(args.toArray());
            } else if (sql.indexOf("?") == sql.lastIndexOf("?") && params.length > 1) {
                sqlArgument.setText(StringUtils.replace(sql, "?", StringUtils.repeat("?", ",", params.length)));
                sqlArgument.setArgs(params);
            } else {
                sqlArgument.setText(sql);
                sqlArgument.setArgs(params);
            }

            return sqlArgument;
        }
    }

    public static String removeOrders(String sql) {
        if (StringUtils.isEmpty(sql)) {
            return sql;
        } else {
            Matcher m = ORDER_PATTERN.matcher(sql);
            if (!m.find()) {
                return sql;
            } else {
                StringBuffer sb = new StringBuffer();
                String s = sql.substring(m.start(), m.end());
                char[] sA = s.toCharArray();
                int start = 0;
                int l = sA.length;

                int i;
                for(i = 0; i < l; ++i) {
                    if (sA[i] == '(') {
                        ++start;
                    } else if (sA[i] == ')') {
                        --start;
                    }

                    if (start < 0) {
                        break;
                    }
                }

                m.appendReplacement(sb, s.substring(i));
                m.appendTail(sb);
                return removeOrders(sb.toString());
            }
        }
    }

    private static boolean isNamedQuery(Object[] params){
        if (params.length == 1 && params[0] instanceof Map) {
            return true;
        }
        return false;
    }
}
